/* =========================================
 *             网关子服务实现 
 * =========================================*/

#pragma once
#include <algorithm>
#include <brpc/server.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <thread>
#include <websocketpp/close.hpp>
#include <websocketpp/connection.hpp>
#include <websocketpp/frame.hpp>
#include "base.pb.h"
#include "gateway_routes.h"
#include "connection.hpp"
#include "../../third/include/httplib.h"
#include "etcd.hpp"
#include "channel.hpp"
#include "notify.pb.h"
#include "utils.hpp"
#include "data_cache.hpp"
#include "logger.hpp"
#include "gateway.pb.h"
#include "file.pb.h"
#include "user.pb.h"
#include "friend.pb.h"
#include "message_transmit.pb.h"
#include "message_storage.pb.h"
#include "speech_recognition.pb.h"


namespace im_server {

class GatewayServer;
class GatewayServerBuilder;
using GatewayServerPtr = std::shared_ptr<GatewayServer>;
using GatewayServerBuilderPtr = std::shared_ptr<GatewayServerBuilder>;

class GatewayServer
{
public:
    GatewayServer(const shared::dal::RedisPtr& redisClient,
            const shared::infra::RpcServiceManagerPtr& rpcServiceMgr,
            const shared::infra::DiscoveryPtr& rpcSvrDisc,
            uint16_t websocketPort, uint16_t httpPort,
            const std::string& fileServiceName, const std::string& userServiceName, 
            const std::string& speechServiceName, const std::string& friendServiceName, 
            const std::string& transmitServiceName, const std::string& messageServiceName
        )
        : sessionCache_(std::make_shared<shared::dal::Session>(redisClient))
        , statusCache_(std::make_shared<shared::dal::Status>(redisClient))
        , rpcServiceMgr_(rpcServiceMgr), rpcSvrDisc_(rpcSvrDisc)
        , websocketPort_(websocketPort), httpPort_(httpPort)
        , connections_(std::make_shared<Connection>())
        , fileServiceName_(fileServiceName)
        , userServiceName_(userServiceName)
        , speechServiceName_(speechServiceName)
        , friendServiceName_(friendServiceName)
        , transmitServiceName_(transmitServiceName)
        , messageServiceName_(messageServiceName)
    {
        wsServerInit();    // websocket服务器初始化
        httpServerInit();  // http服务器初始化
    }
    void start() { wsServer_.run(); }
private:
    void wsServerInit()
    {
        wsServer_.set_access_channels(websocketpp::log::alevel::none);
        wsServer_.init_asio();
        wsServer_.set_open_handler(std::bind(&GatewayServer::onOpen, this, std::placeholders::_1));
        wsServer_.set_close_handler(std::bind(&GatewayServer::onClose, this, std::placeholders::_1));    
        auto onMessageCb = std::bind(
            &GatewayServer::onMessage, this, std::placeholders::_1, std::placeholders::_2
        );
        wsServer_.set_message_handler(onMessageCb);
        wsServer_.set_reuse_addr(true);
        wsServer_.listen(websocketPort_);
        wsServer_.start_accept();
    }
    void httpServerInit()
    {
        #define HTTP_REGISTER_POST(PATH, FUNC) \
            httpServer_.Post(PATH, (httplib::Server::Handler)std::bind(FUNC, this, std::placeholders::_1, std::placeholders::_2));

        HTTP_REGISTER_POST(USER_REGISTER         , &GatewayServer::userRegister);
        HTTP_REGISTER_POST(ACCOUNT_LOGIN         , &GatewayServer::accountLogin);
        HTTP_REGISTER_POST(PHONE_LOGIN           , &GatewayServer::phoneLogin);
        HTTP_REGISTER_POST(GET_PHONE_VERIFY_CODE , &GatewayServer::getPhoneVerifyCode);
        HTTP_REGISTER_POST(GET_USERINFO          , &GatewayServer::getUserInfo);
        HTTP_REGISTER_POST(SET_USER_AVATAR       , &GatewayServer::setUserAvatar);
        HTTP_REGISTER_POST(SET_USER_NICKNAME     , &GatewayServer::setUserNickname);
        HTTP_REGISTER_POST(SET_USER_DESCRIPTION  , &GatewayServer::setUserDescription);
        HTTP_REGISTER_POST(SET_USER_PHONE        , &GatewayServer::setUserPhone);
        HTTP_REGISTER_POST(GET_FRIEND_LIST       , &GatewayServer::getFriendtList);
        HTTP_REGISTER_POST(FRIEND_APPLY          , &GatewayServer::friendApply);
        HTTP_REGISTER_POST(FRIEND_APPLY_PROCESS  , &GatewayServer::friendApplyProcess);
        HTTP_REGISTER_POST(FRIEND_REMOVE         , &GatewayServer::friendRemove);
        HTTP_REGISTER_POST(FRIEND_SEARCH         , &GatewayServer::friendSearch);
        HTTP_REGISTER_POST(FRIEND_GET_PENDING_EV , &GatewayServer::friendGetPendingEv);
        HTTP_REGISTER_POST(GET_CHATSESSION_LIST  , &GatewayServer::getChatSessionList);
        HTTP_REGISTER_POST(CHATSESSION_CREATE    , &GatewayServer::chatSessionCreate);
        HTTP_REGISTER_POST(GET_CHATSESSION_MEMBER, &GatewayServer::getChatSessionMember);
        HTTP_REGISTER_POST(GET_RECENT_MESSAGE    , &GatewayServer::getRecentHisMsg);
        HTTP_REGISTER_POST(GET_RANGE_MESSAGE     , &GatewayServer::getRangeHisMsg);
        HTTP_REGISTER_POST(MESSAGE_SEARCH        , &GatewayServer::hisMsgSearch);
        HTTP_REGISTER_POST(NEW_MESSAGE           , &GatewayServer::newMessage);
        HTTP_REGISTER_POST(GET_SINGLE_FILE       , &GatewayServer::getSingleFile);
        HTTP_REGISTER_POST(GET_MULTI_FILE        , &GatewayServer::getMultiFile);
        HTTP_REGISTER_POST(PUT_SINGLE_FILE       , &GatewayServer::putSingleFile);
        HTTP_REGISTER_POST(PUT_MULTI_FILE        , &GatewayServer::putMultiFile);
        HTTP_REGISTER_POST(SPEECH_RECOGNITION    , &GatewayServer::speechRecognition);

        httpThread_ = std::thread([this](){
            httpServer_.listen("0.0.0.0", httpPort_);
        });

        httpThread_.detach();
    }
    void onOpen(websocketpp::connection_hdl hdl) 
    {
        // 在服务端视角, 长连接的正式建立维护在客户端发送消息之后
        // 因此在onOpen回调内不需要做任何操作(长连接的维护延迟到收到消息之后)
        LOG_DEBUG("websocket长连接建立成功: {}", (size_t)wsServer_.get_con_from_hdl(hdl).get());
    }
    void onClose(websocketpp::connection_hdl hdl) 
    {
        // 1. 通过连接对象, 获取登录ID 用户ID
        auto conn = wsServer_.get_con_from_hdl(hdl);
        std::string userId, sessionId;
        if(!connections_->getClient(conn, userId, sessionId)) {
            
            LOG_WARN("长连接断开 --- 未查询到该连接匹配的客户端");
            return ;
        }
        // 2. 移除缓存
        sessionCache_->remove(sessionId);
        statusCache_->remove(userId);
        connections_->remove(conn);
        LOG_DEBUG("[session:{} user:{}] 长连接已断开:{}", sessionId, userId, (size_t)conn.get());
    }
    void keepAlive(WsServer::connection_ptr conn)
    {
        if(!conn || conn->get_state() != websocketpp::session::state::open) {
            LOG_DEBUG("连接状态异常, 结束连接保活机制");
            return;
        }
        conn->ping("");
        wsServer_.set_timer(60000, std::bind(&GatewayServer::keepAlive, this, conn));
    }
    void onMessage(websocketpp::connection_hdl hdl, WsServer::message_ptr msg)
    {
        // 1. 取出长连接操作句柄
        auto conn = wsServer_.get_con_from_hdl(hdl);
        // 2. 反序列化消息内容, 提取登录会话ID
        im_proto::ClientAuthenticationReq req;
        if(!req.ParseFromString(msg->get_payload())) {
            LOG_ERROR(" 消息正文反序列化失败, 无法进行长连接身份识别");
            wsServer_.close(hdl, websocketpp::close::status::invalid_payload, "消息正文反序列化失败");
            return;
        }
        // 3. 会话缓存校验该会话的合法性
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("登录会话({})不存在, 长连接身份识别失败!", sessionId);
            wsServer_.close(hdl, websocketpp::close::status::policy_violation, "登录会话不合法");
            return;
        }
        // 5. 会话鉴权成功后, 维护管理该客户端的长连接
        connections_->insert(conn, userId.value(), sessionId);
        LOG_DEBUG("[session:{} user:{}] 新增维护长连接:{}", sessionId, userId.value(), (size_t)conn.get());

        // 6. 开启长连接保活机制
        keepAlive(conn);
    }
private:
    void userRegister(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::UserRegisterReq req;
        im_proto::UserRegisterRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[用户名注册] 请求正文反序列化失败");
            return errResp(req, resp, response, "[用户名注册] 请求正文反序列化失败");
        }
        // 2. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.UserRegister(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 3. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");
    }
    void accountLogin(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::AccountLoginReq req;
        im_proto::AccountLoginRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[账号登录] 请求正文反序列化失败");
            return errResp(req, resp, response, "[账号登录] 请求正文反序列化失败");
        }
        // 2. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.AccountLogin(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 3. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");
    }
    void phoneLogin(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::PhoneLoginReq req;
        im_proto::PhoneLoginRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[手机号登录] 请求正文反序列化失败");
            return errResp(req, resp, response, "[手机号登录] 请求正文反序列化失败");
        }
        // 2. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.PhoneLogin(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 3. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");
    }
    void getPhoneVerifyCode(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::PhoneVerifyCodeReq req;
        im_proto::PhoneVerifyCodeRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取短信验证码] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取短信验证码] 请求正文反序列化失败");
        }
        // 2. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.GetPhoneVerifyCode(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 3. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");
    }
    void getUserInfo(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetUserInfoReq req;
        im_proto::GetUserInfoRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取用户信息] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取用户信息] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.GetUserInfo(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void setUserAvatar(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::SetUserAvatarReq req;
        im_proto::SetUserAvatarRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[修改用户头像] 请求正文反序列化失败");
            return errResp(req, resp, response, "[修改用户头像] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.SetUserAvatar(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void setUserNickname(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::SetUserNicknameReq req;
        im_proto::SetUserNicknameRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[修改用户昵称] 请求正文反序列化失败");
            return errResp(req, resp, response, "[修改用户昵称] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.SetUserNickname(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void setUserDescription(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::SetUserDescriptionReq req;
        im_proto::SetUserDescriptionRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[修改用户签名] 请求正文反序列化失败");
            return errResp(req, resp, response, "[修改用户签名] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.SetUserDescription(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void setUserPhone(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::SetUserPhoneNumberReq req;
        im_proto::SetUserPhoneNumberRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[修改用户手机号] 请求正文反序列化失败");
            return errResp(req, resp, response, "[修改用户手机号] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到用户管理子服务
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "用户管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.SetUserPhoneNumber(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "用户管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getFriendtList(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetFriendListReq req;
        im_proto::GetFriendListRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取好友列表] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取好友列表] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.GetFriendList(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void friendApply(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::FriendAddReq req;
        im_proto::FriendAddRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[好友申请] 请求正文反序列化失败");
            return errResp(req, resp, response, "[好友申请] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_req_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendAdd(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        } 
        // 4. 业务处理成功 && 该请求的接收方用户客户端在线(长连接存在), 向接收方进行好友申请事件通知
        auto conn = connections_->getConnection(req.recv_user_id());
        if(resp.success() && conn) {
            auto reqUserInfo = _getUserInfo(req.request_id(), userId.value());  // 获取申请人自己的用户信息给接收方
            if(!reqUserInfo) {
                LOG_ERROR("[{}] 获取当前客户端登录的用户信息失败", req.request_id());
                return errResp(req, resp, response, "获取当前客户端登录的用户信息失败");
            }
            im_proto::NotifyMessage notifyMsg;
            notifyMsg.set_notify_type(im_proto::NotifyType::FRIEND_ADD_APPLY_NOTIFY);
            notifyMsg.mutable_friend_add_apply()->mutable_user_info()->CopyFrom(reqUserInfo.value());
            conn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void friendApplyProcess(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::FriendAddProcessReq req;
        im_proto::FriendAddProcessRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[好友申请处理] 请求正文反序列化失败");
            return errResp(req, resp, response, "[好友申请处理] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto recvUserId = sessionCache_->getUserId(sessionId);   // 从缓存中拿到的用户ID匹配的发起该http请求的用户 
        if(!recvUserId) {                                        // 因此这里拿到的userId = 这条好友申请的接收方
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_recv_user_id(recvUserId.value());      // !!! 从缓存拿到的是此次好友申请的被申请人
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendAddProcess(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        } 
        // 4. 业务处理成功
        if(resp.success()) {
            auto applyRecvUserInfo = _getUserInfo(req.request_id(), recvUserId.value());     // 获取该好友申请的接收用户信息
            if(!applyRecvUserInfo) {
                LOG_ERROR("[{}] 获取当前客户端登录的用户信息失败", req.request_id());
                return errResp(req, resp, response, "获取当前客户端登录的用户信息失败");
            }
            auto applyReqUserInfo = _getUserInfo(req.request_id(), req.req_user_id());      // 获取该好友申请的申请用户信息
            if(!applyReqUserInfo) {
                LOG_ERROR("[{}] 获取当前用户所申请添加的用户信息失败", req.request_id());
                return errResp(req, resp, response, "获取当前用户所申请添加的用户信息失败");
            }
            auto reqUserConn = connections_->getConnection(req.req_user_id()); 
            // 4-1 给申请者进行处理结果通知
            if(reqUserConn) {   
                im_proto::NotifyMessage notifyMsg;
                notifyMsg.set_notify_type(im_proto::NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
                auto processResult = notifyMsg.mutable_friend_process_result();
                processResult->set_agree(req.agree());
                // 给申请者反馈对方的处理结果, 因此带的是对方的用户信息
                processResult->mutable_user_info()->CopyFrom(applyRecvUserInfo.value());  
                reqUserConn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }
            // 4-2 如果申请通过, 通知双方新会话创建
            if(req.agree() && reqUserConn) {
                im_proto::NotifyMessage notifyMsg;
                notifyMsg.set_notify_type(im_proto::NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                auto chatSessionInfo = notifyMsg.mutable_new_chat_session_info()->mutable_chat_session_info();
                chatSessionInfo->set_chat_session_id(resp.new_session_id());
                chatSessionInfo->set_single_chat_friend_id(recvUserId.value());     // 对于申请方, 它的好友是该申请的接收方
                chatSessionInfo->set_chat_session_name(applyRecvUserInfo->nickname());
                chatSessionInfo->set_avatar(applyRecvUserInfo->avatar());
                reqUserConn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }
            auto recvUserConn = connections_->getConnection(recvUserId.value()); 
            if(req.agree() && recvUserConn) {
                im_proto::NotifyMessage notifyMsg;
                notifyMsg.set_notify_type(im_proto::NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                auto chatSessionInfo = notifyMsg.mutable_new_chat_session_info()->mutable_chat_session_info();
                chatSessionInfo->set_chat_session_id(resp.new_session_id());
                chatSessionInfo->set_single_chat_friend_id(req.req_user_id());     // 对于接收方, 它的好友是该申请的发起者
                chatSessionInfo->set_chat_session_name(applyReqUserInfo->nickname());
                chatSessionInfo->set_avatar(applyReqUserInfo->avatar());
                recvUserConn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");   
    }
    void friendRemove(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::FriendRemoveReq req;
        im_proto::FriendRemoveRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[好友删除] 请求正文反序列化失败");
            return errResp(req, resp, response, "[好友删除] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto reqUserId = sessionCache_->getUserId(sessionId);
        if(!reqUserId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_req_user_id(reqUserId.value());    // 好友删除的发起者就是此处的申请者
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendRemove(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        } 
        // 4. 业务处理成功 && 该请求的接收方用户客户端在线(长连接存在), 向接收方进行好友申请事件通知
        auto conn = connections_->getConnection(req.recv_user_id());
        if(resp.success() && conn) {
            im_proto::NotifyMessage notifyMsg;
            notifyMsg.set_notify_type(im_proto::NotifyType::FRIEND_REMOVE_NOTIFY);
            notifyMsg.mutable_friend_remove()->set_user_id(reqUserId.value());      // 通知接收方谁删了ta(也就是删除好友的申请者)
            conn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
        } 
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void friendSearch(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::FriendSearchReq req;
        im_proto::FriendSearchRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[用户搜索] 请求正文反序列化失败");
            return errResp(req, resp, response, "[用户搜索] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.FriendSearch(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void friendGetPendingEv(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetPendingFriendEventListReq req;
        im_proto::GetPendingFriendEventListRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取待处理的好友申请列表] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取待处理的好友申请列表] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.GetPendingFriendEventList(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getChatSessionList(const httplib::Request& request, httplib::Response& response)
    {   
        // 1. 反序列化http正文
        im_proto::GetChatSessionListReq req;
        im_proto::GetChatSessionListRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取聊天会话列表] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取聊天会话列表] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.GetChatSessionList(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void chatSessionCreate(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::ChatSessionCreateReq req;
        im_proto::ChatSessionCreateRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[聊天会话创建] 请求正文反序列化失败");
            return errResp(req, resp, response, "[聊天会话创建] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.ChatSessionCreate(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        }
        // 4. 通知该会话的成员
        if(resp.success()) {
            for(auto& memberId : req.member_id_list()) {
                auto conn = connections_->getConnection(memberId);
                if(!conn) {
                    LOG_DEBUG("未找到群聊成员({})所在客户端的长连接", memberId);
                    continue;
                }
                im_proto::NotifyMessage notifyMsg;
                notifyMsg.set_notify_type(im_proto::NotifyType::CHAT_SESSION_CREATE_NOTIFY);
                notifyMsg.mutable_new_chat_session_info()->mutable_chat_session_info()->CopyFrom(resp.chat_session_info());
                conn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }
        }
        // 5. 将rpc调用的结果响应给客户端
        resp.clear_chat_session_info();     // 这个数据只用于服务端内部
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getChatSessionMember(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetChatSessionMemberReq req;
        im_proto::GetChatSessionMemberRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取会话成员列表] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取会话成员列表] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到好友管理子服务
        auto channel = rpcServiceMgr_->choose(friendServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 好友管理子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "好友管理子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FriendService_Stub stub(channel.get());
        stub.GetChatSessionMember(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 好友管理子服务调用失败", req.request_id());
            return errResp(req, resp, response, "好友管理子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getRecentHisMsg(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetRecentHisMsgReq req;
        im_proto::GetRecentHisMsgRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取最近N条历史消息] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取最近N条历史消息] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到消息存储子服务
        auto channel = rpcServiceMgr_->choose(messageServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 消息存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "消息存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::MsgStorageService_Stub stub(channel.get());
        stub.GetRecentHisMsg(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 消息存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "消息存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getRangeHisMsg(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetRangeHisMsgReq req;
        im_proto::GetRangeHisMsgRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[按时间范围获取历史消息] 请求正文反序列化失败");
            return errResp(req, resp, response, "[按时间范围获取历史消息] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到消息存储子服务
        auto channel = rpcServiceMgr_->choose(messageServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 消息存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "消息存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::MsgStorageService_Stub stub(channel.get());
        stub.GetRangeHisMsg(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 消息存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "消息存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void hisMsgSearch(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::HisMsgSearchReq req;
        im_proto::HisMsgSearchRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[历史消息搜索] 请求正文反序列化失败");
            return errResp(req, resp, response, "[历史消息搜索] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到消息存储子服务
        auto channel = rpcServiceMgr_->choose(messageServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 消息存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "消息存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::MsgStorageService_Stub stub(channel.get());
        stub.HisMsgSearch(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 消息存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "消息存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void newMessage(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::NewMessageReq req;
        im_proto::NewMessageRsp resp;       // 将transmitResp构造成NewMessageRsp返回给客户端的响应
        im_proto::GetTransmitTargetRsp transmitResp;        // 业务处理返回的响应
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[消息发送] 请求正文反序列化失败");
            return errResp(req, resp, response, "[消息发送] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到消息转发子服务
        auto channel = rpcServiceMgr_->choose(transmitServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 消息转发子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "消息转发子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::MsgTransmitService_Stub stub(channel.get());
        stub.GetTransmitTarget(&ctl, &req, &transmitResp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 消息转发子服务调用失败", req.request_id());
            return errResp(req, resp, response, "消息转发子服务调用失败");
        }
        // 4. 消息转发: 通知所有与该消息相关的用户
        if(transmitResp.success()) {
            for(auto& userId : transmitResp.target_id_list()) {
                auto conn = connections_->getConnection(userId);
                if(!conn) {
                    LOG_DEBUG("未找到消息转发目标用户({})所在客户端的长连接", userId);
                    continue;
                }
                im_proto::NotifyMessage notifyMsg;
                notifyMsg.set_notify_type(im_proto::NotifyType::CHAT_MESSAGE_NOTIFY);
                notifyMsg.mutable_new_message_info()->mutable_message_info()->CopyFrom(transmitResp.message());
                conn->send(notifyMsg.SerializeAsString(), websocketpp::frame::opcode::value::binary);
            }
        }

        // 5. 将rpc调用的结果响应给客户端
        resp.set_request_id(transmitResp.request_id());
        resp.set_success(transmitResp.success());
        resp.set_errmsg(transmitResp.errmsg());
        response.set_content(resp.SerializeAsString(), "application/x-protobuf"); 
    }
    void getSingleFile(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetSingleFileReq req;
        im_proto::GetSingleFileRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取单文件] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取单文件] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到文件存储子服务
        auto channel = rpcServiceMgr_->choose(fileServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 文件存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "文件存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FileService_Stub stub(channel.get());
        stub.GetSingleFile(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 文件存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "文件存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void getMultiFile(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::GetMultiFileReq req;
        im_proto::GetMultiFileRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[获取多文件] 请求正文反序列化失败");
            return errResp(req, resp, response, "[获取多文件] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到文件存储子服务
        auto channel = rpcServiceMgr_->choose(fileServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 文件存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "文件存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FileService_Stub stub(channel.get());
        stub.GetMultiFile(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 文件存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "文件存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void putSingleFile(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::PutSingleFileReq req;
        im_proto::PutSingleFileRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[上传单文件] 请求正文反序列化失败");
            return errResp(req, resp, response, "[上传单文件] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到文件存储子服务
        auto channel = rpcServiceMgr_->choose(fileServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 文件存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "文件存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FileService_Stub stub(channel.get());
        stub.PutSingleFile(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 文件存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "文件存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void putMultiFile(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::PutMultiFileReq req;
        im_proto::PutMultiFileRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[上传多文件] 请求正文反序列化失败");
            return errResp(req, resp, response, "[上传多文件] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到文件存储子服务
        auto channel = rpcServiceMgr_->choose(fileServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 文件存储子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "文件存储子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::FileService_Stub stub(channel.get());
        stub.PutMultiFile(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 文件存储子服务调用失败", req.request_id());
            return errResp(req, resp, response, "文件存储子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
    void speechRecognition(const httplib::Request& request, httplib::Response& response)
    {
        // 1. 反序列化http正文
        im_proto::SpeechRecognitionReq req;
        im_proto::SpeechRecognitionRsp resp;
        if(!req.ParseFromString(request.body)) {
            LOG_ERROR("[语音识别] 请求正文反序列化失败");
            return errResp(req, resp, response, "[语音识别] 请求正文反序列化失败");
        }
        // 2. 身份鉴权
        const std::string& sessionId = req.session_id();
        auto userId = sessionCache_->getUserId(sessionId);
        if(!userId) {
            LOG_ERROR("该登录会话[{}]关联的用户不存在", sessionId);
            return errResp(req, resp, response, "该登录会话关联的用户不存在");
        }
        req.set_user_id(userId.value());
        // 3. 将请求转发到语音识别子服务
        auto channel = rpcServiceMgr_->choose(speechServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 语音识别子服务节点不存在!", req.request_id());
            return errResp(req, resp, response, "语音识别子服务节点不存在");
        }  
        brpc::Controller ctl;
        im_proto::SpeechService_Stub stub(channel.get());
        stub.SpeechRecognition(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 语音识别子服务调用失败", req.request_id());
            return errResp(req, resp, response, "语音识别子服务调用失败");
        }
        // 4. 将rpc调用的结果响应给客户端
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");  
    }
private:
    std::optional<im_proto::UserInfo> _getUserInfo(const std::string& rid, const std::string& uid)
    {
        im_proto::GetUserInfoReq req;
        req.set_request_id(rid);
        req.set_user_id(uid);
        auto channel = rpcServiceMgr_->choose(userServiceName_);
        if(!channel) {
            LOG_ERROR("[{}] 用户管理子服务节点不存在!", req.request_id());
            return std::nullopt;
        }  
        im_proto::GetUserInfoRsp resp;
        brpc::Controller ctl;
        im_proto::UserService_Stub stub(channel.get());
        stub.GetUserInfo(&ctl, &req, &resp, nullptr);
        if(ctl.Failed()) {
            LOG_ERROR("[{}] 用户管理子服务调用失败", req.request_id());
            return std::nullopt;
        } 
        return resp.user_info();
    }

    template<typename REQ, typename RESP>
    void errResp(REQ req, RESP resp, httplib::Response& response, const std::string& errmsg)
    {
        resp.set_success(false);
        resp.set_errmsg(errmsg);
        response.set_content(resp.SerializeAsString(), "application/x-protobuf");
    }
private:
    shared::dal::SessionPtr sessionCache_;       // 客户端会话数据保存
    shared::dal::StatusPtr statusCache_;         // 客户端状态数据保存

    shared::infra::RpcServiceManagerPtr rpcServiceMgr_;     // rpc的服务管理对象
    shared::infra::DiscoveryPtr rpcSvrDisc_;                // rpc服务发现对象

    WsServer wsServer_;           // websocket服务器
    httplib::Server httpServer_;  // http服务器
    std::thread httpThread_;      // http服务线程
    uint16_t websocketPort_;
    uint16_t httpPort_;

    ConnectionPtr connections_;     // 长连接维护

    std::string fileServiceName_;       // 文件存储子服务名称
    std::string userServiceName_;       // 用户管理子服务名称
    std::string speechServiceName_;     // 语音识别子服务名称
    std::string friendServiceName_;     // 好友管理子服务名称
    std::string transmitServiceName_;   // 消息转发子服务名称
    std::string messageServiceName_;    // 消息存储子服务名称
};

class GatewayServerBuilder
{
public:
    // 构造redis客户端对象
    void makeRedisObject(const std::string& host, uint16_t port, int db, bool keepAlive)
    {
        redisClient_ = shared::dal::RedisClientFactory::create(host, port, db, keepAlive);
    }
    // 构造Rpc服务发现客户端对象
    void makeRpcSvrDiscoverer(const std::string& host, const std::string& baseServiceName,
            const std::string& fileServiceName, const std::string& userServiceName, 
            const std::string& speechServiceName, const std::string& friendServiceName, 
            const std::string& transmitServiceName, const std::string& messageServiceName)
    {
        fileServiceName_ = fileServiceName;     
        userServiceName_ = userServiceName;     
        speechServiceName_ = speechServiceName;     
        friendServiceName_ = friendServiceName;     
        transmitServiceName_ = transmitServiceName;     
        messageServiceName_ = messageServiceName;    

        rpcServiceMgr_ = std::make_shared<shared::infra::RpcServiceManager>();
        rpcServiceMgr_->declared(fileServiceName);
        rpcServiceMgr_->declared(userServiceName);
        rpcServiceMgr_->declared(speechServiceName);
        rpcServiceMgr_->declared(friendServiceName);
        rpcServiceMgr_->declared(transmitServiceName);
        rpcServiceMgr_->declared(messageServiceName_);

        auto putCb = std::bind(
            &shared::infra::RpcServiceManager::onServiceOnline, rpcServiceMgr_.get(),
            std::placeholders::_1, std::placeholders::_2
        );
        auto delCb = std::bind(
            &shared::infra::RpcServiceManager::onServiceOffline, rpcServiceMgr_.get(),
            std::placeholders::_1, std::placeholders::_2
        );
        rpcSvrDisc_ = std::make_shared<shared::infra::Discovery>(host, baseServiceName, putCb, delCb);
    }
    void setNetworkPort(int websocketPort, int httpPort) 
    {
        websocketPort_ = websocketPort;
        httpPort_ = httpPort;
    }
    GatewayServerPtr build()
    {
        if (!redisClient_) {
            LOG_ERROR("还未初始化redis缓存模块!");
            abort();
        }
        if(!rpcSvrDisc_) {
            LOG_ERROR("还未初始化服务发现模块!");
            abort();
        }
        if (!rpcServiceMgr_) {
            LOG_ERROR("还未初始化rpc服务管理模块!");
            abort();
        }
        return std::make_shared<GatewayServer>(
            redisClient_, rpcServiceMgr_, rpcSvrDisc_, websocketPort_, httpPort_,
            fileServiceName_, userServiceName_, speechServiceName_,
            friendServiceName_, transmitServiceName_, messageServiceName_
        );
    }
private:
    shared::dal::RedisPtr redisClient_;     // 用户的临时数据缓存句柄

    shared::infra::RpcServiceManagerPtr rpcServiceMgr_;     // rpc的服务管理对象
    shared::infra::DiscoveryPtr rpcSvrDisc_;                // rpc服务发现对象

    uint16_t websocketPort_;
    uint16_t httpPort_;
    
    std::string fileServiceName_;       // 文件存储子服务名称
    std::string userServiceName_;       // 用户管理子服务名称
    std::string speechServiceName_;     // 语音识别子服务名称
    std::string friendServiceName_;     // 好友管理子服务名称
    std::string transmitServiceName_;   // 消息转发子服务名称
    std::string messageServiceName_;    // 消息存储子服务名称
};


}